package com.lyz.file.impl;

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.log4j.Logger;

import com.lyz.config.ConfigFactory;
import com.lyz.config.IConfig;
import com.lyz.file.IFileFetcher;
import com.lyz.file.IFileProcess;
import com.lyz.file.IFileQueue;
import com.lyz.util.BaseTypeUtil;
import com.lyz.util.FileUtil;
import com.lyz.util.PropertiesUtil;
import com.lyz.util.SleepUtil;

public class LogFileFetcher extends Thread implements IFileFetcher{

	private final static Logger logger = Logger.getLogger(LogFileFetcher.class);

	private IFileQueue queue = null;

	private IConfig proUtil = null;

	private String lastFileInQueue = null;

	private int fetchInterval = 0;
	
	private String tag = null;
	
	private IFileProcess proc = null;
	
	

	/**
	 * 该方法需要在实例化之后立即调用
	 * @param queue
	 * @param tag
	 */
	public IFileFetcher initFetcher(IFileQueue queue, IFileProcess proc, String tag){
		this.queue = queue;
		this.tag = tag;
		this.proc = proc;

		proUtil = ConfigFactory.getConfig();
		fetchInterval = proUtil.getFetchInteval(tag);
		
		return this;
	}

	public void run() {
		logger.info("start fetcher service,tag is "+tag);
		while (true) {
			
			getNewFile();
			/*每隔5秒去尝试获取新文件*/
			SleepUtil.sleepForCertainTime(5000);
		}
	}
	/**
	 * 根据队列尾部的文件推测下一个需要进入队列的文件
	 */
	public void getNewFile() {
		
		/*初始化，获取队列尾部的文件,队尾的文件必须保证是一个格式正确的文件*/
		if(lastFileInQueue == null){
			lastFileInQueue = queue.getLastOne();			
		}		
		File file = null;
		long time = getDateTimeFromFileName(lastFileInQueue);
		/*如果文件名非法，则不获取*/
		if(time<=0){
			logger.info("invalid file name in the queue:"+lastFileInQueue);
			return;
		}
		time = time + fetchInterval;
		/*获取文件队列尾部之后所有的文件，并将其加入队列*/
		while (time < System.currentTimeMillis()) {
			String newFileName = proUtil.getFileStart(tag)
					+ proUtil.getFileSplit(tag)
					+ BaseTypeUtil
							.getStrDateTime(time, proUtil.getDateFormat(tag))
					+ proUtil.getFileEndWith(tag);
			logger.info("try to fetch new file:"+proUtil.getLogDirectory(tag) + "/" + newFileName);
			file = new File(proUtil.getLogDirectory(tag) + "/" + newFileName);
			// logger.debug("try to fetch file:"+newFileName);
			// 文件存在，并且不是队列末尾的那个文件,则将其加入队列
			if (file.exists() && !newFileName.equals(lastFileInQueue)) {
				queue.addFile(newFileName);
				lastFileInQueue = newFileName;
				logger.info("add " + newFileName + " to the queue..."
						+ queue.size() + " files in queue!");
			}

			time = time + fetchInterval;
		}
	}
	
	
	

	public long getDateTimeFromFileName(String fileName){
		
		long dateTime = 0;
		if(fileName == null || "".equals(fileName.trim())){
			return -1;
		}
		String date = null;
		try {
			date = BaseTypeUtil.getSubString(fileName, proUtil.getFileStart(tag)+proUtil.getFileSplit(tag), proUtil.getFileEndWith(tag));
			/*注意：默认的时间转换只扫描前边的字符，如果符合一个时间格式就不返回错误，
			 * 比如2013-03-05.log是能够正确解析的
			 * 此处需要再加一层判断保证类似于2013-03-05.log的不能够被解析
			 * */
			if(date==null || proUtil.getDateFormat(tag).length()!=date.length()){
				logger.warn("format error of date:"+date);
				return -1;
			}
			/*日期格式不全，则补全（当前日期）*/
			dateTime = BaseTypeUtil.getFormatTime(proUtil.getDateFormat(tag), date);

		} catch (Exception e) {
			logger.warn("format error of date:"+date+" dateformat is "+proUtil.getDateFormat(tag)+" date is "+date+" fileName is "+fileName);
			return -1;
		}
		
		return dateTime;
		
	}
	
	
	
	/**
	 * 调用线程的start方法
	 */
	public void start(){
		super.start();
	}
	
	public String createFileName(){
		String dateTime = null;
		String start = proUtil.getFileStart(tag);
		String end = proUtil.getFileEndWith(tag);
		String split = proUtil.getFileSplit(tag);
		long timeout = proUtil.getFileTimeout(tag);
		if (timeout >= 0) {
			dateTime = new SimpleDateFormat(proUtil.getDateFormat(tag))
					.format(new Date(System.currentTimeMillis()
							- proUtil.getFileTimeout(tag)));
		} else {/*默认没有超时文件*/
			dateTime = new SimpleDateFormat(proUtil.getDateFormat(tag))
					.format(new Date(0));
		}

		return start + split + dateTime + end;
	}
	/**
	 * 初始化文件队列，获取文件列表，然后根据过滤规则（以什么开始，以什么结束，中间日期格式是否正确）进行文件过滤，
	 * 过滤之后的文件会被按照中间部分的时间进行排序，较早时间的放在队列前边，这样保证队尾的文件是最新生成的。
	 * 在getNewFile时，会根据队尾的文件中的时间预测下一个文件的文件名，预测规则为队尾文件的时间加上一个时间
	 * 间隔。
	 */
	public void initFileQueue(){
		//get file list, sub folder files are not included
		/*对于动态时间的，只获取一天之中的日志*/
		List<String> fileList = new FileUtil().getFileList(proUtil.getLogDirectory(tag), proUtil.getFileStart(tag), proUtil.getFileEndWith(tag),false);	
		if(fileList==null || fileList.isEmpty()){
			logger.info("fileList is empty!");
			return;
		}
		SortedMap<Long,String> sortedMap = new TreeMap<Long, String>();
		long timeout = proUtil.getFileTimeout(tag);
		long currentTime = System.currentTimeMillis();
		long lashParseFileTime = getDateTimeFromFileName(proc.getNextFile());
		
		//filter and sort file by datetime asc
		if(timeout>=0){
			for(String f : fileList){
				long tmpTime = getDateTimeFromFileName(f);
				/*忽略错误时间格式的文件*/
				if(tmpTime<=0){
					continue;
				}
				//ignor files that have been handled
				if(lashParseFileTime>tmpTime){
					continue;
				}
				if(currentTime-tmpTime<=timeout){
					sortedMap.put(tmpTime, f);
				}
			}
		}else{//no filter if timeout < 0
			for(String f : fileList){
				long tmpTime = getDateTimeFromFileName(f);
				/*忽略错误时间格式的文件*/
				if(tmpTime<=0){
					continue;
				}
				//ignor files that have been handled
				if(lashParseFileTime>tmpTime){
					continue;
				}
				/*对文件进行排序，保证较早生成的文件的优先处理*/
				sortedMap.put(tmpTime, f);
			}
		}
		
		//add file name to the queue
		Set<Long> set = sortedMap.keySet();
		for(Iterator<Long> iter=set.iterator();iter.hasNext();){
			String file = sortedMap.get(iter.next());
			queue.addFile(file);
			logger.info(file+" is inserted in the queue!tag="+tag);
		}
		logger.info("init file queue,"+queue.getFileCount()+" files are filled in the queue!");
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
//		try {
//			System.out.println(new SimpleDateFormat("HH_mm").parse("00_00").getTime());
//			System.out.println(new SimpleDateFormat("yyyy-MM-dd HH_mm").parse("2014-08-15 12_00").getTime());
//		} catch (ParseException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		
//		System.out.println(LogFileFetcher.getTime("HH_mm", "12_00"));
//		System.out.println(LogFileFetcher.getTime("dd HH_mm", "15 12_00"));
//		System.out.println(LogFileFetcher.getTime("MM-dd HH_mm", "08-15 12_00"));
//		System.out.println(LogFileFetcher.getTime("yyyy-MM-dd HH_mm", "2014-08-15 12_00"));
	}

}
